<template>
  <page-card title="角色管理"
             :sub-title="!this.$route.query.id ? '新增':'编辑'"
             :need-back="true">
    <slot name="form" />
    <a-row v-if="!$slots.form"
           :gutter="16">
      <a-col :span="8">
        <a-card title="角色信息"
                :bodyStyle="{height:'450px',overflow: 'auto'}">
          <a-form :form="form"
                  :label-col="{ span: 6 }"
                  :wrapper-col="{ span: 14 }">
            <a-form-item label="ID"
                         v-show="false">
              <a-input v-decorator="['id']" />
            </a-form-item>
            <a-form-item label="名称">
              <a-input :maxLength="20"
                       v-decorator="['name', {
                         rules: [{
                           required: true,transform: value => value ? value.trim() : '', message: '请输入角色名称'
                         }]
                       }]" />
            </a-form-item>
            <a-form-item label="编码">
              <a-input :maxLength="20"
                       v-decorator="['code',{
                         rules: [{
                           required: true,transform: value => value ? value.trim() : '', message: '请输入编码'
                         }]
                       }]" />
            </a-form-item>
            <a-form-item label="排序号">
              <a-input-number :min="1"
                              v-decorator="['orderNo', {
                                rules: [{
                                  required: true, message: '请输入排序号'
                                }]
                              }]" />
            </a-form-item>
            <a-form-item label="角色分类">
              <a-select allowClear
                        v-decorator="['roleClassId', {
                          rules: [{
                            required: false, message: '请选择分类'
                          }]
                        }]">
                <a-select-option v-for="(item,index) in this.roleClass"
                                 :value="item.id"
                                 :key="index">
                  {{ item.roleClassName }}
                </a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item>
              <span slot="label">
                岗位
                <a-tooltip title="角色绑定岗位，用户新增时选择岗位自动授权该角色权限">
                  <a-icon type="question-circle-o" />
                </a-tooltip>
              </span>
              <a-select allowClear
                        v-decorator="['jobRankId', {
                          rules: [{
                            required: false, message: '请选择岗位'
                          }]
                        }]">
                <a-select-option v-for="(item,index) in this.JobList"
                                 :value="item.id"
                                 :key="index">
                  {{ item.jobName }}
                </a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item>
              <span slot="label">
                所属机构
                <a-tooltip title="角色的归属机构">
                  <a-icon type="question-circle-o" />
                </a-tooltip>
              </span>
              <ZSelectUnit :limit="1"
                           v-decorator="['affiliatedUnitIds', {
                             rules: [{
                               required: false, message: '请选择所属机构'
                             }]
                           }]"></ZSelectUnit>
            </a-form-item>
            <a-form-item>
              <span slot="label">
                管理机构
                <a-tooltip title="对选择机构的管理权限">
                  <a-icon type="question-circle-o" />
                </a-tooltip>
              </span>
              <ZSelectUnit v-decorator="['managementUnitIds', {
                rules: [{
                  required: false, message: '请选择管理机构'
                }]
              }]"></ZSelectUnit>
            </a-form-item>
            <a-form-item>
              <span slot="label">
                共享机构
                <a-tooltip title="共享该角色权限至其他机构">
                  <a-icon type="question-circle-o" />
                </a-tooltip>
              </span>
              <ZSelectUnit v-decorator="['shareUnitIds', {
                rules: [{
                  required: false, message: '请选择角共享机构'
                }]
              }]"></ZSelectUnit>
            </a-form-item>
            <a-form-item label="是否为测试角色"
                         v-show="false">
              <z-switch-one-zero :disabled="!!roleId"
                                 checked-children="是"
                                 un-checked-children="否"
                                 v-decorator="['isTest', {
                                   valuePropName: 'checked',
                                   initialValue: '0'
                                 }] " />
              <div style="color:red;height:10px;margin-top: -10px;">测试角色类型新增后不能修改</div>
            </a-form-item>
            <!-- <a-form-item v-if="editFlag"
                          label="类型">
                  <a-radio-group v-decorator="['type',{
                    rules: [{
                      required: true, message: '请选择类型'
                    }]
                  }]">
                    <a-radio value="1">
                      全局
                    </a-radio>
                    <a-radio value="2">
                      单位
                    </a-radio>
                  </a-radio-group>
                </z-switch></a-form-model-item></a-form-item> -->
            <a-form-item label="是否启用">
              <z-switch-one-zero checked-children="是"
                                 un-checked-children="否"
                                 v-decorator="['status']" />
            </a-form-item>
            <a-form-item label="说明">
              <a-textarea :maxLength="120"
                          placeholder="菜单功能描述，不超过120字"
                          v-decorator="['remark']"
                          style="height:80px"></a-textarea>
            </a-form-item>
          </a-form>
        </a-card>
      </a-col>
      <a-col :span="8">
        <a-card title="菜单权限"
                :bodyStyle="{height:'450px',overflow: 'auto'}">
          <div class="tree-box">
            <div>
              <a-checkbox :indeterminate="indeterminateMeau"
                          :checked="allCheckFlag"
                          @change="allCheck">
                全选
              </a-checkbox>
            </div>
            <div style="padding:10px 0">
              <a-tree ref="menuTree"
                      checkable
                      v-model="checkedKeys"
                      :tree-data="data"
                      :defaultExpandAll="true"
                      :expanded-keys="expandedKeys"
                      @expand="handleExpand"
                      @check="handleTree" />
            </div>
          </div>
        </a-card>
      </a-col>
      <a-col :span="8">
        <a-card title="应用权限"
                :bodyStyle="{height:'450px',overflow: 'auto'}">
          <div class="tree-box">
            <div>
              <a-checkbox :indeterminate="indeterminate"
                          :checked="checkAll"
                          @change="onAppCheckAllChange">
                全选
              </a-checkbox>
            </div>
            <div style="padding:10px 0">
              <a-checkbox-group v-model="checkedList"
                                :options="plainOptions"
                                @change="onAppChange" />
            </div>
          </div>
        </a-card>
      </a-col>
    </a-row>
    <div style="text-align:center; padding:30px">
      <a-space size="small">
        <slot name="buttons" />
        <template v-if="!$slots.buttons">
          <a-button v-if="$route.query.id && hasPermission('delete')"
                    action
                    @click="handleDelete"
                    style="width:80px;">删除</a-button>
          <a-button type="primary"
                    action
                    @click="handleSave"
                    style="width:80px;">保存</a-button>
        </template>
      </a-space>
    </div>
  </page-card>
</template>

<script>
import Vue from 'vue'
import { Card } from 'ant-design-vue'
import ArrayUtil from '@zh/common-utils/utils/array'
import {
  saveOrUpdate,
  getById,
  getOrderNo,
  del,
  getInitApps,
  getRoleClassList
} from '../../api/role/index'
import { getAllUserMenu } from '../../api/auth/index'
import { getJobRanklist } from '../../api/job/index'
import clone from 'clone'

Vue.use(Card)

export default {
  props: {
    onSave: {
      type: Function,
      default: null
    },
    onDelete: {
      type: Function,
      default: null
    }
  },
  data () {
    return {
      roleId: '',
      treeMap: {},
      data: [],
      expandedKeys: [],
      checkedKeys: [],
      appList: [],
      checkedList: [],
      checkAll: false,
      indeterminate: false,
      allData: [],
      indeterminateMeau: false,
      allSelectedNodes: [],
      plainOptions: [],
      editFlag: true,
      form: this.$form.createForm(this, { name: 'coordinated' }),
      roleClass: [],
      JobList: [],
      allCheckFlag: false
    }
  },
  computed: {
    // indeterminate () {
    //   return this.checkedList.length > 0
    // }
  },
  created () {
    getRoleClassList({}).then(res => {
      this.roleClass = res
    })
    getJobRanklist().then(res => {
      this.JobList = res
    })

    this.roleId = this.$route.query.id
    if (this.$slots.form) {
      // 表单被重写后，不再加载数据
      return
    }
    this.loadActionList(() => {
      if (!this.$route.query.id) {
        getOrderNo().then((response) => {
          this.getInitApps()
          this.form.setFieldsValue(response)
          this.indeterminateMeau = false
        })
      } else {
        getById(this.$route.query.id).then((response) => {
          this.checkedList = response.appIds
          this.getInitApps()
          // 级联勾选权限树
          response.menuIds.map((i) => {
            if (
              i.checked == '1' &&
              this.treeMap[i.id] &&
              !this.treeMap[i.id].children
            ) {
              // 只勾选叶子节点
              this.checkedKeys.push(i.id)
            }
          })

          // 级联勾选父节点
          Object.keys(this.treeMap).map((key) => {
            this.cascadeCheckedNode(this.treeMap[key])
          })

          // 表单赋值
          const values = {}
          for (const k in this.form.fieldsStore.fieldsMeta) {
            response.hasOwnProperty(k) && (values[k] = response[k])
          }
          this.editFlag = response.editFlag
          this.form.setFieldsValue(values)
          this.setAllChecked()
        })
      }
    })
  },
  methods: {
    handleTree (selectedKeys, info) {
      // 已勾选子节点以及半勾选状态的父节点
      this.allSelectedNodes = selectedKeys.concat(info.halfCheckedKeys)
      this.checkedKeys = selectedKeys
      this.setAllChecked()
    },
    // 设置菜单全选状态
    setAllChecked () {
      let count = 0
      // 获取树形菜单第一层节点的勾选数量，只需要判断树形菜单第一层节点的勾选状态即可推断出全选按钮状态
      for (const node of this.data) {
        if (this.checkedKeys.includes(node.id)) {
          count++
        }
      }
      if (count === 0) {
        // count为 0 时，表示第一层所有节点没有勾选，代表未勾选
        this.indeterminateMeau = this.checkedKeys.length > 0
        this.allCheckFlag = false
      } else if (count === this.data.length) {
        // count等于树形菜单第一层节点数量时，代表全选状态
        this.indeterminateMeau = false
        this.allCheckFlag = true
      } else {
        // count在 0 和 树形菜单第一层节点数量之间时，代表半选状态
        this.indeterminateMeau = true
        this.allCheckFlag = false
      }
    },
    // 权限全选
    allCheck () {
      if (!this.allCheckFlag) {
        let dateall = this.allData
        this.checkedKeys = dateall
        this.allSelectedNodes = dateall
        this.allCheckFlag = true
      } else {
        this.checkedKeys = []
        this.allSelectedNodes = []
        this.allCheckFlag = false
      }
      this.indeterminateMeau = false
    },
    // 将输入的内容与显示的内容进行匹配
    filterOption (value, option) {
      return option.componentOptions.children[0].text.indexOf(value) >= 0
    },
    getInitApps () {
      let this_ = this
      getInitApps().then((res) => {
        this_.appList = res || []
        this_.plainOptions = this_.appList.map((item) => {
          return { label: item.name, value: item.id }
        })
        // 初始化全选
        this.checkAll = this.checkedList.length == this_.plainOptions.length
        this.indeterminate =
          !!this.checkedList.length &&
          this.checkedList.length < this.plainOptions.length
      })
    },
    onAppChange (checkedList) {
      this.indeterminate =
        !!checkedList.length && checkedList.length < this.plainOptions.length
      this.checkAll = checkedList.length === this.plainOptions.length
    },
    onAppCheckAllChange (e) {
      // eslint-disable-next-line no-unused-expressions
      ; (this.checkedList = e.target.checked
        ? this.plainOptions.map((item) => item.value)
        : []),
        (this.indeterminate = false),
        (this.checkAll = e.target.checked)
    },
    cascadeCheckedNode (node) {
      if (node.children) {
        node.children.map((child) => {
          this.cascadeCheckedNode(child)
        })
      }
      if (node.parentId) {
        const pnode = this.treeMap[node.parentId]
        if (pnode) {
          const notCheckedNode = pnode.children.find((n) => {
            return !this.checkedKeys.includes(n.id)
          })
          if (!notCheckedNode) {
            // 没找到未勾选的子节点时，将父节点添加到checkedKeys
            !this.checkedKeys.includes(pnode.id) &&
              this.checkedKeys.push(pnode.id)
          }
        }
      }
    },
    /**
     * 加载权限树
     */
    loadActionList (callback) {
      this.allData = []
      getAllUserMenu({ useType: 'menuAuthority' }).then((response) => {
        response = response || []
        response.map((i) => {
          i.title = i.name
          i.key = i.id
          if (!i.parentId || i.parentId == '' || i.parentId == '0') {
            i.parentId = null
          }
          this.allData.push(i.id)
        })
        const { nodeList, nodeMap } = ArrayUtil.toTree(
          response,
          'id',
          'parentId'
        )
        this.data = nodeList
        this.treeMap = nodeMap
        // this.indeterminateMeau = nodeList.length > 0
        callback()
      })
    },
    /**
     * 树节点展开折叠
     */
    handleExpand (expandedKeys) {
      this.expandedKeys = expandedKeys
    },
    handleSave () {
      this.form.validateFields((err, values) => {
        if (err) {
          return
        }
        if (this.checkedKeys.length == 0) {
          this.message.error('请选择菜单权限')
          return
        }
        values.appIds = this.checkedList
        values.menuIds = this.getHalfCheckedKeys()
          .map((i) => {
            return { id: i, checked: '0' }
          })
          .concat(
            this.checkedKeys.map((i) => {
              return { id: i, checked: '1' }
            })
          )
        if (this.onSave) {
          this.onSave(values).then((response) => {
            this.$router.go(-1)
          })
        } else {
          saveOrUpdate(values).then((response) => {
            this.$router.go(-1)
          })
        }
      })
    },
    handleDelete () {
      const me = this
      me.confirm({
        content: '确定删除？',
        okText: '是',
        cancelText: '否',
        onOk () {
          if (me.onDelete != null) {
            me.onDelete(me.form.getFieldValue('id'), me.form).then((res) => {
              me.$router.go(-1)
            })
          } else {
            del(me.form.getFieldValue('id')).then((res) => {
              me.$router.go(-1)
            })
          }
        }
      })
    },
    /**
     * 递归获取半选节点
     */
    getHalfCheckedKeys () {
      const halfCheckedKeys = []
      Object.keys(this.treeMap).map((key) => {
        const node = this.treeMap[key]
        if (this.checkedKeys.includes(key)) {
          return
        }
        if (node.children) {
          let checkedCount = 0
          node.children.map((n) => {
            if (this.checkedKeys.includes(n.id)) {
              checkedCount++
            }
          })
          if (checkedCount < node.children.length && checkedCount > 0) {
            halfCheckedKeys.push(node.id)
          }
        }
      })
      clone(halfCheckedKeys).map((key) => {
        let parentNode = this.treeMap[this.treeMap[key].parentId]
        while (parentNode) {
          if (!halfCheckedKeys.includes(parentNode.id)) {
            halfCheckedKeys.push(parentNode.id)
          }
          parentNode = this.treeMap[parentNode.parentId]
        }
      })
      return halfCheckedKeys
    }
  }
}
</script>

<style lang="less" scoped>
::v-deep .ant-checkbox-group-item {
  width: 100%;
  padding: 5px 0;
}
</style>
